package org.teamswift.crow.rbac.service;

import com.google.common.base.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.teamswift.crow.rbac.dto.CrowAuthorizeDto;
import org.teamswift.crow.rbac.entity.CrowAuthority;
import org.teamswift.crow.rbac.entity.CrowRole;
import org.teamswift.crow.rbac.enums.CrowRowPermissionLevel;
import org.teamswift.crow.rbac.repository.CrowAuthorityRepository;
import org.teamswift.crow.rbac.repository.CrowRoleRepository;
import org.teamswift.crow.rest.common.ICrowService;
import org.teamswift.crow.rest.exception.CrowErrorMessage;
import org.teamswift.crow.rest.exception.impl.DataNotFoundException;
import org.teamswift.crow.rest.utils.CrowMessageUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

@Service
@Transactional(rollbackFor = Exception.class)
public class CrowRoleService implements ICrowService<Integer, CrowRole, CrowRoleRepository> {

    private final CrowAuthorityRepository crowAuthorityRepository;

    private final CrowRoleRepository crowRoleRepository;

    public CrowRoleService(CrowAuthorityRepository crowAuthorityRepository, CrowRoleRepository crowRoleRepository) {
        this.crowAuthorityRepository = crowAuthorityRepository;
        this.crowRoleRepository = crowRoleRepository;
    }

    @Override
    public CrowRole findOneById(Integer integer) {
        CrowRole role = ICrowService.super.findOneById(integer);
        if(role == null) {
            throw new DataNotFoundException(
                    CrowMessageUtil.error(
                            CrowErrorMessage.NotFoundByID
                    )
            );
        }
        List<CrowAuthority> authorities = crowAuthorityRepository.findAllByRoleIdOrderByPermissionResourceAscActionAsc(role.getId());
        role.setAuthorities(
                new HashSet<>(authorities)
        );

        return role;
    }

    /**
     * @param dtoList
     * @return
     */
    public List<CrowAuthority> authorize(CrowRole role, List<CrowAuthorizeDto> dtoList) {

        crowAuthorityRepository.deleteAllByRoleId(role.getId());

        List<CrowAuthority> authorities = new ArrayList<>();
        dtoList.forEach(dto -> {
            if(dto.getAction().isEmpty()
                    || Strings.isNullOrEmpty(dto.getPermissionResource())) {
                return;
            }
            CrowAuthority crowAuthority = new CrowAuthority();
            crowAuthority.setRoleId(role.getId());
            crowAuthority.setAction(dto.getAction());
            crowAuthority.setPermissionResource(dto.getPermissionResource());
            crowAuthority.setRowPermissionLevel(
                    dto.getRowPermissionLevel() == null ? CrowRowPermissionLevel.All : dto.getRowPermissionLevel()
            );

            authorities.add(crowAuthority);
        });

        return crowAuthorityRepository.saveAll(authorities);
    }

    @Override
    public CrowRoleRepository getRepository() {
        return crowRoleRepository;
    }
}
